﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Taxonomy;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using WebPart = System.Web.UI.WebControls.WebParts.WebPart;

//http://blogs.itacs.de/mk/Lists/Beitraege/Post.aspx?ID=2

namespace mAdcOW.SharePoint.TaxonomyFilter.TaxonomyFilterWebPart
{
    [ToolboxItem(false)]
    public class TaxonomyFilterWebPart : WebPart, ITaxonomyFilterValueProvider
    {
        private string _label = "Current filter";
        [Category("Extended Settings"), Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         WebDisplayName("Label"), WebDescription("Label to be displayed before the selected value")]
        public string Label
        {
            get { return _label; }
            set { _label = value; }
        }

        private string _noValue = "None";
        [Category("Extended Settings"), Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         WebDisplayName("No value"), WebDescription("Value to show if no filter is selected")]
        public string NoValue
        {
            get { return _noValue; }
            set { _noValue = value; }
        }

        private string _clearText = "Clear";
        [Category("Extended Settings"), Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         WebDisplayName("Clear link text"), WebDescription("Text to show on clear link")]
        public string Clear
        {
            get { return _clearText; }
            set { _clearText = value; }
        }

        private bool _showCurrentFilter = true;
        [Category("Extended Settings"), Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         WebDisplayName("Show current filter"), WebDescription("Show or hide the selected filter")]
        public bool ShowCurrentFilter
        {
            get { return _showCurrentFilter; }
            set { _showCurrentFilter = value; }
        }

        private bool _showClearButton = true;
        [Category("Extended Settings"), Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
         WebDisplayName("Show clear link"), WebDescription("Show or hide the clear link")]
        public bool ShowClearButton
        {
            get { return _showClearButton; }
            set { _showClearButton = value; }
        }

        private readonly TaxonomyFilter _filter;
        private Guid _termStoreId;
        private Guid _termSetId;

        public TaxonomyFilterWebPart()
        {
            _filter = new TaxonomyFilter(this);
        }

        public new WebPartManager WebPartManager
        {
            get { return base.WebPartManager; }
        }

        // Returns / to the values of the filter has WebPart 
        public bool HasValue
        {
            get { return string.IsNullOrEmpty(_filterValues) == false; }
        }

        // Sample values 
        private string _filterValues = string.Empty;

        public string FilterValue
        {
            get { return _filterValues; }
        }

        private string _filterData = string.Empty;

        public string FilterData
        {
            get { return _filterData; }
        }

        ///  
        /// Passes the connection to the TaxonomyFilterüür XsltListViewWebPart 
        ///  
        [ConnectionProvider("Taxonomy filter", "TaxonomyFilterConnectionTrans", AllowsMultipleConnections = true)]
        public ITransformableFilterValues SetFilterConnection()
        {
            return _filter;
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            EnableViewState = false;

            RegisterMenu();

            foreach (WebPartConnection connection in WebPartManager.Connections)
            {
                var transformer = connection.Transformer as TransformableFilterValuesToParametersTransformer;
                if (transformer == null) continue;

                string[] consumerFieldNames = transformer.ConsumerFieldNames;

                XsltListViewWebPart webPart = WebPartManager.WebParts[connection.ConsumerID] as XsltListViewWebPart;
                if (webPart == null) continue;

                SPList list = SPContext.Current.Web.Lists.GetList(webPart.ListId, false);
                TaxonomyField field = list.Fields.GetField(consumerFieldNames[0]) as TaxonomyField;
                if (field == null) continue;

                if (_termSetId != Guid.Empty && _termSetId != field.TermSetId ||
                    _termStoreId != Guid.Empty && _termStoreId != field.SspId)
                {
                    throw new ApplicationException("Multiple webparts have to be filtered on the same taxonomy");
                }

                AddHeader();

                _termStoreId = field.SspId;
                _termSetId = field.TermSetId;

                TaxonomySession session = new TaxonomySession(SPContext.Current.Site);
                TermStore termStore = session.TermStores[field.SspId];

                TermSet termSet = termStore.GetTermSet(field.TermSetId);
                TermCollection termCollection = termSet.GetAllTerms();

                var allTerms = termCollection.ToList();
                List<Term> rootTerms = termCollection.Where(t => t.Parent == null).ToList();
                BuildMenu(rootTerms, allTerms, termSet.CustomSortOrder, 1);
            }
        }

        private void AddHeader()
        {
            if (!_showClearButton && !_showCurrentFilter) return;
            HtmlGenericControl container = new HtmlGenericControl("div");
            container.Attributes["class"] = "taxfilter";

            if (_showCurrentFilter)
            {
                HtmlGenericControl label = new HtmlGenericControl("label");
                label.InnerText = _label + ": ";
                label.Attributes["for"] = "pick";
                label.Attributes["class"] = "taxfilter label";

                HtmlGenericControl pick = new HtmlGenericControl("span");
                pick.Attributes["id"] = "pick";
                pick.InnerText = _noValue;
                pick.Attributes["class"] = "taxfilter current";

                container.Controls.Add(label);
                container.Controls.Add(pick);
            }
            if (_showClearButton)
            {
                LinkButton clearFilter = new LinkButton();
                clearFilter.Text = "Clear";
                clearFilter.Click += clearFilter_Click;
                clearFilter.CssClass = "taxfilter clear";
                container.Controls.Add(clearFilter);
            }
            Controls.Add(container);
        }

        private void RegisterMenu()
        {
            ScriptLink.Register(Page, "/_layouts/mAdcOW.SharePoint.TaxonomyFilter/js/jquery-1.9.1.js", false);
            ScriptLink.Register(Page, "/_layouts/mAdcOW.SharePoint.TaxonomyFilter/js/jquery-ui-1.10.2.custom.min.js", false);
            ScriptLink.Register(Page, "/_layouts/mAdcOW.SharePoint.TaxonomyFilter/js/taxmenu.js", false);
            CssRegistration.Register("/_layouts/mAdcOW.SharePoint.TaxonomyFilter/css/jquery-ui-1.10.2.custom.css");
        }

        /// <summary>
        /// Recursive function to build the menu
        /// </summary>
        /// <param name="levelTerms"></param>
        /// <param name="allTerms"></param>
        /// <param name="customSort"></param>
        /// <param name="level"></param>
        private void BuildMenu(List<Term> levelTerms, List<Term> allTerms, string customSort, int level)
        {
            if (levelTerms.Count == 0) return;
            levelTerms.ForEach(c => allTerms.Remove(c));
            if (!string.IsNullOrEmpty(customSort))
            {
                string[] order = customSort.Split(':');
                levelTerms.Sort(
                    (l, r) => Array.IndexOf(order, l.Id.ToString()).CompareTo(Array.IndexOf(order, r.Id.ToString())));
            }
            Literal ul = new Literal { Text = string.Format("<ul id='{0}{1}' class='level{1}'>", "taxmenu", level) };
            Controls.Add(ul);
            bool childrenAdded = false;
            foreach (var term in levelTerms)
            {
                int[] descendantsId = TaxonomyField.GetWssIdsOfTerm(SPContext.Current.Site, _termStoreId, _termSetId,
                                                                    term.Id, true, 500);
                if (descendantsId.Length == 0) continue; // term has not been used for tagging
                childrenAdded = true;
                string idString = string.Join(",", new List<int>(descendantsId).ConvertAll(i => i.ToString()).ToArray());

                string uniqueId = term.Id.ToString().Replace("-", "");

                Literal li = new Literal { Text = "<li>" };
                li.ID = "lit" + uniqueId;
                Controls.Add(li);
                LinkButton lb = new LinkButton
                    {
                        ID = "tax" + uniqueId,
                        Text = term.Labels.First().Value
                    };
                lb.Click += filter_Click;
                lb.Attributes["value"] = idString;
                lb.Attributes["data"] = "1," + term.Id;
                Controls.Add(lb);
                Guid termId = term.Id;
                List<Term> children = allTerms.Where(t => t.Parent != null && t.Parent.Id == termId).ToList();
                BuildMenu(children, allTerms, term.CustomSortOrder, ++level);
                Controls.Add(new Literal { Text = "</li>" });
            }
            if (!childrenAdded)
            {
                Controls.Remove(ul);
            }
            else
            {
                Controls.Add(new Literal { Text = "</ul>" });
            }
        }

        private void filter_Click(object sender, EventArgs e)
        {
            LinkButton lb = (LinkButton)sender;
            _filterValues = lb.Attributes["value"];
            _filterData = lb.Attributes["data"];
            string uniqueId = "lit" + _filterData.Split(',')[1].Replace("-", "");
            Literal selected = Controls.OfType<Literal>().FirstOrDefault(c => c.ID == uniqueId);
            if (selected != null)
            {
                selected.Text = "<li class='taxselected'>";
            }
            if (!_showCurrentFilter) return;
            HtmlGenericControl pick =
                Page.GetAll().OfType<HtmlGenericControl>().FirstOrDefault(c => c.Attributes["id"] == "pick");
            if (pick != null) pick.InnerText = lb.Text;
        }

        private void clearFilter_Click(object sender, EventArgs e)
        {
            _filterValues = null;
            _filterData = null;
            if (!_showCurrentFilter) return;
            HtmlGenericControl pick =
                Page.GetAll().OfType<HtmlGenericControl>().FirstOrDefault(c => c.Attributes["id"] == "pick");
            if (pick != null) pick.InnerText = _noValue;
        }
    }
}